package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/6/4
 * @description
 **/
public class BallExchangeElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {

    float[] translateX = new float[3], translateY = new float[3];

    private Paint mPaint = new Paint();
    private Color ballColor;
    private int duration;
    private boolean isInit = false;
    private static final int VALUE_3 = 3;
    private static final int VALUE_2 = 2;

    private BallExchangeElement(IComponentCallback iComponentCallback) {
        this.callback = iComponentCallback;
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        if (!isInit) {
            return null;
        }
        ArrayList<AnimatorValue> mAnimators = new ArrayList<>();
        float startX = getWidth() / 5;
        float startY = getWidth() / 5;
        for (int i = 0; i < VALUE_3; i++) {
            final int index = i;
            AnimatorValue translateXaxisAnim = new AnimatorValue();
            translateXaxisAnim.setDuration(duration);
            translateXaxisAnim.setCurveType(Animator.CurveType.LINEAR);
            translateXaxisAnim.setLoopedCount(-1);
            translateXaxisAnim.setValueUpdateListener((animatorValue, v) -> {
                if (index == 1) {
                    translateX[index] = translationXaxisOne(startX, getWidth(), v);
                } else if (index == VALUE_2) {
                    translateX[index] = translationXaxisTwo(startX, getWidth(), v);
                } else {
                    translateX[index] = translationXaxisThree(startX, getWidth(), v);
                }
                callback.reflushComponent();
            });

            AnimatorValue translateYaxisAnim = new AnimatorValue();
            translateYaxisAnim.setDuration(duration);
            translateYaxisAnim.setCurveType(Animator.CurveType.LINEAR);
            translateYaxisAnim.setLoopedCount(-1);
            translateYaxisAnim.setValueUpdateListener((animatorValue, v) -> {
                if (index == 1) {
                    translateY[index] = translationYaxisOne(startY, getHeight() - startY, v);
                } else if (index == VALUE_2) {
                    translateY[index] = translationYaxisTwo(startY, getHeight() - startY, v);
                } else {
                    translateY[index] = translationYaxisThree(startY, getHeight() - startY, v);
                }
                callback.reflushComponent();
            });
            mAnimators.add(translateXaxisAnim);
            mAnimators.add(translateYaxisAnim);
        }
        return mAnimators;
    }

    protected float translationXaxisOne(float a, float b, float v) {
        float res = 0;
        if (v <= (float) 1 / VALUE_3) {
            res = VALUE_3 * (b / VALUE_2 - a) * v + b / VALUE_2;
        } else if (v > (float) 1 / VALUE_3 && v <= (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (VALUE_2 * a - b) * v + VALUE_2 * b - VALUE_3 * a;
        } else if (v > (float) VALUE_2 / VALUE_3) {
            res = (VALUE_3 * b / VALUE_2 - VALUE_3 * a) * v + VALUE_3 * a - b;
        }
        return res;
    }

    protected float translationXaxisTwo(float a, float b, float v) {
        float res = 0;
        if (v <= (float) 1 / VALUE_3) {
            res = VALUE_3 * (VALUE_2 * a - b) * v + b - a;
        } else if (v > (float) 1 / VALUE_3 && v <= (float) VALUE_2 / VALUE_3) {
            res = (VALUE_3 * b / VALUE_2 - VALUE_3 * a) * v + VALUE_2 * a - b / VALUE_2;
        } else if (v > (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (b / VALUE_2 - a) * v + VALUE_2 * a - b / VALUE_2;
        }
        return res;
    }

    protected float translationXaxisThree(float a, float b, float v) {
        float res = 0;
        if (v <= (float) 1 / VALUE_3) {
            res = VALUE_3 * (b / VALUE_2 - a) * v + a;
        } else if (v > (float) 1 / VALUE_3 && v <= (float) VALUE_2 / VALUE_3) {
            res = (VALUE_3 * b / VALUE_2 - VALUE_3 * a) * v + a;
        } else if (v > (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (VALUE_2 * a - b) * v + VALUE_3 * b - 5 * a;
        }
        return res;
    }

    protected float translationYaxisOne(float a, float b, float v) {
        float res = 0;
        if (v <= (float) 1 / VALUE_3) {
            res = VALUE_3 * (b - a) * v + a;
        } else if (v > (float) 1 / VALUE_3 && v <= (float) VALUE_2 / VALUE_3) {
            res = b;
        } else if (v > (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (a - b) * v + VALUE_3 * b - VALUE_2 * a;
        }
        return res;
    }

    protected float translationYaxisTwo(float a, float b, float v) {
        float res = 0;
        if (v <= (float) 1 / VALUE_3) {
            res = b;
        } else if (v > (float) 1 / VALUE_3 && v <= (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (a - b) * v + VALUE_2 * b - a;
        } else if (v > (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (b - a) * v + VALUE_3 * a - VALUE_2 * b;
        }
        return res;
    }

    protected float translationYaxisThree(float a, float b, float v) {
        float res = 0;
        if (v <= (float) 1 / VALUE_3) {
            res = VALUE_3 * (a - b) * v + b;
        } else if (v > (float) 1 / VALUE_3 && v <= (float) VALUE_2 / VALUE_3) {
            res = VALUE_3 * (b - a) * v + VALUE_2 * a - b;
        } else if (v > (float) VALUE_2 / VALUE_3) {
            res = b;
        }
        return res;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public BaseAnimationController.IAnimationController<AnimatorValue> initAnimationController() {
        return this;
    }

    @Override
    public void initPaint() {
        super.initPaint();
        mPaint.setColor(ballColor);
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setAntiAlias(true);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        if (!isInit) {
            isInit = true;
            startAnimators();
            return;
        }
        for (int i = 0; i < VALUE_3; i++) {
            canvas.save();
            canvas.translate(translateX[i], translateY[i]);
            canvas.drawCircle(0, 0, getWidth() / 10, mPaint);
            canvas.restore();
        }
    }

    private void apply(BallExchangeBuilder builder) {
        this.ballColor = builder.ballColor == null ? Color.WHITE : builder.ballColor;
        this.duration = builder.duration > 0 ? builder.duration : 2000;
    }

    public static class BallExchangeBuilder {
        private IComponentCallback iComponentCallback;
        private Color ballColor;
        private int duration;

        public BallExchangeBuilder(IComponentCallback iComponentCallback) {
            this.iComponentCallback = iComponentCallback;
        }

        public BallExchangeBuilder setBallColor(Color ballColor) {
            this.ballColor = ballColor;
            return this;
        }

        public BallExchangeBuilder setDuration(int duration) {
            this.duration = duration;
            return this;
        }

        public BallExchangeElement build() {
            BallExchangeElement ballExchangeElement = new BallExchangeElement(iComponentCallback);
            ballExchangeElement.apply(this);
            return ballExchangeElement;
        }
    }
}
